package com.lineage.server;

import com.lineage.DatabaseFactory;
import com.lineage.server.datatables.lock.ServerReading;
import com.lineage.server.utils.PerformanceTimer;
import com.lineage.server.utils.SQLUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class IdFactory {
  private static final Log _log = LogFactory.getLog(IdFactory.class);
  
  private static IdFactory _instance;
  
  private Object _monitor;
  
  private AtomicInteger _nextId;
  
  private int _yuanbaoId;
  
  private int _gamId;
  
  private int _bankId;
  
  private int _PayId;
  
  private int _BusinessId;
  
  private final ArrayList<Integer> _yuanbaoList;
  
  private final ArrayList<Integer> _gamblingList;
  
  private final ArrayList<Integer> _bankList;
  
  private final ArrayList<Integer> _PayList;
  
  private final ArrayList<Integer> _BusinessList;
  
  private int _BigHotId;
  
  private int _starId;
  
  private final ArrayList<Integer> _BigHotblingList;
  
  private final ArrayList<Integer> _starblingList;
  
  private int _curId;
  
  private ArrayList<Integer> idList;
  
  private int i;
  
  private boolean isLoadState;
  
  public static IdFactory get() {
    if (_instance == null)
      _instance = new IdFactory(); 
    return _instance;
  }
  
  public static IdFactory getId() {
    if (_instance == null)
      _instance = new IdFactory(); 
    return _instance;
  }
  
  public static IdFactory getInstance() {
    return _instance;
  }
  
  private IdFactory() {
    this._monitor = new Object();
    this._yuanbaoList = new ArrayList<>();
    this._gamblingList = new ArrayList<>();
    this._bankList = new ArrayList<>();
    this._PayList = new ArrayList<>();
    this._BusinessList = new ArrayList<>();
    this._BigHotblingList = new ArrayList<>();
    this._starblingList = new ArrayList<>();
    this.idList = new ArrayList<>();
    this.i = 0;
    this.isLoadState = false;
    resetId();
    if (this.idList.size() > 1) {
      while (this.i + 1 < this.idList.size()) {
        if (((Integer)this.idList.get(this.i + 1)).intValue() - ((Integer)this.idList.get(this.i)).intValue() > 1) {
          this._curId = ((Integer)this.idList.get(this.i)).intValue() + 1;
          break;
        } 
        this.i++;
      } 
      if (this._curId > 0) {
        _log.info("目前对像使用回收ID: " + this._curId);
      } else {
        loadState();
        _log.info("目前对像使用新ID: " + this._curId);
      } 
    } else {
      loadState();
      _log.info("目前对像使用新ID: " + this._curId);
    } 
  }
  
  public int nextId() {
    synchronized (this._monitor) {
      if (this.isLoadState) {
        int n = ++this._curId;
        return n;
      } 
      if (this._curId + 1 < ((Integer)this.idList.get(this.i + 1)).intValue()) {
        this._curId++;
      } else {
        this.i++;
        this._curId = 0;
        while (this.i + 1 < this.idList.size()) {
          if (((Integer)this.idList.get(this.i + 1)).intValue() - ((Integer)this.idList.get(this.i)).intValue() > 1) {
            this._curId = ((Integer)this.idList.get(this.i)).intValue() + 1;
            break;
          } 
          this.i++;
        } 
        if (this._curId <= 0)
          loadState(); 
      } 
      int curId = this._curId;
      return curId;
    } 
  }
  
  private void loadState() {
    if (this.idList.size() > 0) {
      this._curId = ((Integer)this.idList.get(this.idList.size() - 1)).intValue() + 1;
      if (this._curId < 128)
        this._curId = 128; 
    } else {
      this._curId = 128;
    } 
    this.isLoadState = true;
  }
  
  private void resetId() {
    Connection con = null;
    PreparedStatement pstm = null;
    ResultSet rs = null;
    try {
      con = DatabaseFactory.get().getConnection();
      pstm = con.prepareStatement(
          "SELECT id FROM (SELECT `id` FROM `character_items` UNION ALL SELECT `id` FROM `character_warehouse` UNION ALL SELECT `id` FROM `character_elf_warehouse` UNION ALL SELECT `id` FROM `clan_warehouse` UNION ALL SELECT `id` FROM `character_shopinfo` UNION ALL SELECT `objid` AS `id` FROM `characters` UNION ALL SELECT `clan_id` AS `id` FROM `clan_data` UNION ALL SELECT `id` FROM `character_teleport` UNION ALL SELECT `id` FROM `character_mail` UNION ALL SELECT `objid` AS `id` FROM `character_pets`) t order by id");
      rs = pstm.executeQuery();
      while (rs.next())
        this.idList.add(Integer.valueOf(rs.getInt("id"))); 
    } catch (SQLException e) {
      _log.error("id数据加载异常!", e);
    } finally {
      SQLUtil.close(rs, pstm, con);
    } 
  }
  
  public int maxId() {
    synchronized (this._monitor) {
      int value = this._nextId.get();
      return value;
    } 
  }
  
  public void addBusinessId(int i) {
    this._BusinessList.add(Integer.valueOf(i));
  }
  
  public int nextBusinessId() {
    this._BusinessId++;
    while (this._BusinessList.contains(Integer.valueOf(this._BusinessId)))
      this._BusinessId++; 
    return this._BusinessId;
  }
  
  public void addPayId(int i) {
    this._PayList.add(Integer.valueOf(i));
  }
  
  public int nextPayId() {
    this._PayId++;
    while (this._PayList.contains(Integer.valueOf(this._PayId)))
      this._PayId++; 
    return this._PayId;
  }
  
  public void addYuanbaoId(int i) {
    this._yuanbaoList.add(Integer.valueOf(i));
  }
  
  public int nextYuanbaoId() {
    this._yuanbaoId++;
    while (this._yuanbaoList.contains(Integer.valueOf(this._yuanbaoId)))
      this._yuanbaoId++; 
    return this._yuanbaoId;
  }
  
  public void addGamId(int i) {
    this._gamblingList.add(Integer.valueOf(i));
  }
  
  public int nextGamId() {
    this._gamId++;
    while (this._gamblingList.contains(Integer.valueOf(this._gamId)))
      this._gamId++; 
    return this._gamId;
  }
  
  public void addBankId(int i) {
    this._bankList.add(Integer.valueOf(i));
  }
  
  public int nextBankId() {
    this._bankId++;
    while (this._bankList.contains(Integer.valueOf(this._bankId)))
      this._bankId++; 
    return this._bankId;
  }
  
  public void addBigHotId(int i) {
    this._BigHotblingList.add(Integer.valueOf(i));
  }
  
  public int nextBigHotId() {
    this._BigHotId++;
    while (this._BigHotblingList.contains(Integer.valueOf(this._BigHotId)))
      this._BigHotId++; 
    return this._BigHotId;
  }
  
  public void addStarId(int i) {
    this._starblingList.add(Integer.valueOf(i));
  }
  
  public int nextStarId() {
    this._starId++;
    while (this._starblingList.contains(Integer.valueOf(this._starId)))
      this._starId++; 
    return this._starId;
  }
  
  public void load() {
    PerformanceTimer timer = new PerformanceTimer();
    Connection cn = null;
    PreparedStatement ps = null;
    ResultSet rs = null;
    try {
      cn = DatabaseFactory.get().getConnection();
      ps = cn.prepareStatement(
          "SELECT MAX(id)+1 AS NEXTID FROM (SELECT `id` FROM `character_items` UNION ALL SELECT `id` FROM `character_warehouse` UNION ALL SELECT `id` FROM `character_elf_warehouse` UNION ALL SELECT `id` FROM `clan_warehouse` UNION ALL SELECT `id` FROM `character_shopinfo` UNION ALL SELECT `objid` AS `id` FROM `characters` UNION ALL SELECT `clan_id` AS `id` FROM `clan_data` UNION ALL SELECT `id` FROM `character_teleport` UNION ALL SELECT `id` FROM `character_mail` UNION ALL SELECT `objid` AS `id` FROM `character_pets`) t");
      rs = ps.executeQuery();
      int id = 0;
      if (rs.next())
        id = rs.getInt("nextid"); 
      if (id < ServerReading.get().minId())
        id = ServerReading.get().minId(); 
      if (id < ServerReading.get().maxId())
        id = ServerReading.get().maxId(); 
      this._nextId = new AtomicInteger(id);
      _log.info("载入已用最大id编号: " + id + "(" + timer.get() + "ms)");
    } catch (SQLException e) {
      _log.error("id数据加载异常!", e);
    } finally {
      SQLUtil.close(rs);
      SQLUtil.close(ps);
      SQLUtil.close(cn);
    } 
  }
}
